API Gateway + LambdaアプリケーションでS3に署名付きURLを生成しリダイレクトする
こんにちは、菊池です。
やりたいこと
リクエストに応じてS3のファイルを加工し、ダウンロードするサーバレスアプリケーションを考えます。
単純なダウンロードであれば、S3から直接ダウンロードさせられますが、リクエストに応じたファイルの加工が必要なため、Lambdaでその処理を実行します。しかし、Lambdaのレスポンスサイズは最大6MBという制限があるため、そのままLambdaのレスポンスでダウンロードさせると、制限にかかるリスクがありました。
そこで、Lambdaで加工したファイルをテンポラリのS3バケットに一度保存し、署名付きURLを生成します。生成した署名付きURLにリダイレクトさせることで、ダウンロードはS3から直接行なってもらうようにします。
署名付きURLの生成と、API Gatewayのリダイレクトは以下の記事を参考にしています。
構築してみる
Lambda関数の作成
まずは、Lambda関数の作成です。Python 3.6のランタイムで以下のコードを実行します。ソースファイルのS3からファイルをコピーし、署名付きURLを生成しています。今回は試しなので特にファイルはいじらず、バケット間のコピーだけを行なっています。
import boto3 def lambda_handler(event, context): SOURCE_BUCKET = event['YOUR_BUCKET'] KEY = event['YOUR_KEY'] TARGET_BUCKET = 'tmp-bucket' s3 = boto3.client('s3') cp_object = s3.copy_object( CopySource = SOURCE_BUCKET + "/" + KEY, Bucket = TARGET_BUCKET, Key = KEY ) header_location = s3.generate_presigned_url( ClientMethod = 'get_object', Params = {'Bucket' : TARGET_BUCKET, 'Key' : KEY}, ExpiresIn = 3600, HttpMethod = 'GET' ) result = {"Location": header_location} return result
元のファイルのS3バケット、ファイルパス(KEY)はリクエストのパラメータを利用します。
また、関数のロールにはS3のFullAccessポリシーを付与しておきましょう。
API Gatewayの作成
API GatewayでAPIを作成します。上記手順で作成したLambda関数を実行するPOSTメソッドを作成します。
作成したメソッドの、[メソッドレスポンス]と[統合レスポンス]を編集し、リダイレクトできるように設定します。
まずはメソッドレスポンスです。デフォルトにあるHTTPステータス、[200]は削除します。そして、[301]のステータスを作成し、レスポンスヘッダーにLocationを追加します。
続いて、統合レスポンスです。 こちらもデフォルトの[200]は削除し、メソッドレスポンスのステータス[301]を追加します。ヘッダーマッピングのLocationに、integration.response.body.Locationを追加し、保存しましょう。
実行してみる
作成したAPIを呼び出してみます。
$ curl -d '{ "YOUR_BUCKET": "SOURCEバケット", "YOUR_KEY": "test/testfile.png" }' -X POST https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/s3 -i HTTP/1.1 301 Moved Permanently Content-Type: application/json Content-Length: 540 Connection: keep-alive Date: Tue, 08 Aug 2017 08:00:40 GMT x-amzn-RequestId: ab481103-7c0f-11e7-8f07-xxxxxxxxxxxx Location: https://tmp-bucket.s3.amazonaws.com/test/testfile.png X-Amzn-Trace-Id: sampled=0;root=1-59896fa7-xxxxxxxxxxxxxxxxxxxxxxxx X-Cache: Miss from cloudfront Via: 1.1 65986f5372ced7baa305aeec49e8e9c9.cloudfront.net (CloudFront) X-Amz-Cf-Id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
このように、301のレスポンスで作成された署名付きURLがLocationに指定されて帰ってきます。このURLにアクセス数すると、ちゃんと指定したファイルがダウンロードできました。
一時保存用のS3バケットは、ライフサイクルポリシーを指定し、一定時間後には削除されるようにしてしまってよいでしょう。
まとめ
以上です。
今回、Boto3での署名付きURLの生成、API Gateway + Lambdaのリダイレクトについてそれぞれ調べていたら、ともにDevelopers.ioの記事に当たりました。これらを組み合わせるだけで簡単にやりたいことを実装できました。